package viper.badRelays;

import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import viper.main.MySQLFunctions;

/**
 * @author Kevin Sin
 * 
 * Revision number: 3
 * Date created: 3/21/10
 * Date of Last Back-up on SVN: 3/21/10
 * 
 * <p>This class is the central class that keeps track of what a user is doing
 * - logged off, in a call, setting up a call, who the callee is...
 */
public class BadRelaysStateManager {
	//-----------------Singleton structure-----------------------------------
	public final static BadRelaysStateManager INSTANCE = new BadRelaysStateManager();
	private BadRelaysStateManager(){
		
	}
	
	public void initialize(){
		//hard-coded drop/transition rates to model realistic network conditions
		drop_rate_lo = 0.01;
		trans_rate_lo = 0.8;		
		
		try{
			datagramSocket = new DatagramSocket(VIPER_PORT);
		} catch (SocketException e) {
			//already an instance up so exit
			System.out.println("Already an instance running - not starting a new one");
			System.exit(1);
		}
	}
	//------------------------------------------------------------------------
	//----------------Represent state of the user-----------------------------
	public enum State {
		LOGGED_OUT, NOT_IN_CALL, DIALING, CALL_DECISION, IN_CALL 
	}
	private State state = State.LOGGED_OUT;
	
	private void setState(State state) {
		this.state = state;
	}

	public State getState() {
		return state;
	}
	
	//----------------------------------------------------------------
	//------------------------thread pool------------------------------
	private ExecutorService pool;
	
	/**
	 * @return pool
	 */
	public ExecutorService getPool() {
		return pool;
	}
	//----------------------------------------------------------------
	//------------------UDPSocket for receiving / sending------------
	private DatagramSocket datagramSocket; //UDP Socket
	
	/**
	 * @return datagramSocket
	 */
	public DatagramSocket getDatagramSocket() {
		return datagramSocket;
	}
	
	public static final int VIPER_PORT = 40052; //UDP port to use
	//----------------------------------------------------------------
	//------------------Bad Relay variables and methods---------------
	
	private int delay;
	private double drop_rate_hi;
	private double drop_rate_lo;
	private double trans_rate_hi;
	private double trans_rate_lo;

	public void setDelay(int delay) {
		this.delay = delay;
	}

	public int getDelay() {
		return delay;
	}

	/**
	 * Sets the packet drop rate when the network is in a bursty/high-loss condition
	 * @param drop_rate_1
	 */
	public void setDrop_Rate_Hi(double drop_rate) {
		this.drop_rate_hi = drop_rate;
	}
	
	public void setDrop_Rate_Lo(double drop_rate){
		this.drop_rate_lo = drop_rate;
	}

	public double getDrop_Rate_Hi() {
		return drop_rate_hi;
	}
	
	public double getDrop_Rate_Lo(){
		return drop_rate_lo;
	}

	/**
	 * Sets the rate at which the network transitions from low-loss to high-loss condition
	 * @param drop_rate_2
	 */
	public void setTransition_Rate_toHi(double drop_rate) {
		this.trans_rate_hi = drop_rate;
	}

	public void setTransition_Rate_toLo(double drop_rate) {
		this.trans_rate_lo = drop_rate;
	}
	
	public double getTransition_Rate_toHi() {
		return trans_rate_hi;
	}
	
	public double getTransition_Rate_toLo(){
		return trans_rate_lo;
	}
	
	private int droppedPacketCount = 0;
	private int delayedPacketCount = 0;
	
	public void setDroppedPacketCount(int droppedPacketCount) {
		this.droppedPacketCount = droppedPacketCount;
	}

	public int getDroppedPacketCount() {
		return droppedPacketCount;
	}

	public void setDelayedPacketCount(int delayedPacketCount) {
		this.delayedPacketCount = delayedPacketCount;
	}

	public int getDelayedPacketCount() {
		return delayedPacketCount;
	}
	//-----------------------------------------------------------------
	//-----------------helper methods for IP addresses-----------------
	/**
	 * @return - IP address in String format
	 */
	public String getIP() {
		String ip = null;
		try {
			InetAddress address = InetAddress.getLocalHost();
			ip = address.getHostAddress();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
		return ip;
	}
	//------------------------------------------------------------------
	//-------other private variables and related methods----------------
	private String username = null; //name that is displayed
	/**
	 * @return
	 * Getter method for username
	 */
	public String getUsername() {
		return username;
	}
	
	/**
	 * @param username
	 * Setter method for username
	 */
	public void setUsername(String username) {
		this.username = username;
	}
	
	//------------------------------------------------------------
	//--------------------State transitions-----------------------
	/**
	 * @param username
	 * Transition from LOGGED_OUT to NOT_IN_CALL
	 */
	public void login(String username){
		setState(State.NOT_IN_CALL);
		
		pool = Executors.newCachedThreadPool();
		pool.execute(new BadRelaysUDPReceiver()); //start UDPReceiver
		
		setUsername(username);
		MySQLFunctions.login(getIP(), username);
		MySQLFunctions.updateStatus(getIP(), MySQLFunctions.STATUS_BAD_RELAY);
		ViperBadRelaysGUI.INSTANCE.changeCard(ViperBadRelaysGUI.RELAYS_CARD);
	}
	
	/**
	 * Transitions from NOT_IN_CALL to LOGGED_OUT
	 */
	public void logout(){
		MySQLFunctions.logout(getIP());
		setState(State.LOGGED_OUT);
		ViperBadRelaysGUI.INSTANCE.getInternalFrame().setVisible(false);
		ViperBadRelaysGUI.INSTANCE.changeCard(ViperBadRelaysGUI.LOGGED_OUT_CARD);
	}
	//----------------------------------------------------------------
	//----------------------exiting the program---------------------
	/**
	 * called by ViperGUI -  when user closes the window,
	 * make sure the user gets logged out
	 */
	public void exit() {
		if(state!=State.LOGGED_OUT)
			logout();
	}
	//----------------------------------------------------------------

}
